home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 276-300 / disk_280 / graph / object / r_t.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  15KB  |  461 lines

  1. /*
  2.  *                 GRAPH, Version 1.00 - 4 August 1989
  3.  *
  4.  *            Copyright 1989, David Gay. All Rights Reserved.
  5.  *            This software is freely redistrubatable.
  6.  */
  7.  
  8. #include <exec/types.h>
  9. #include <intuition/intuition.h>
  10. #include <graphics/text.h>
  11. #include <math.h>
  12. #include <string.h>
  13.  
  14. #include "object.h"
  15. #include "object/function.h"
  16. #include "file.h"
  17. #include "graph.h"
  18. #include "uio.h"
  19. #include "coords.h"
  20. #include "list.h"
  21. #include "grph.h"
  22. #include "user/eval.h"
  23. #include "user/gadgets.h"
  24. #include "tracker.h"
  25.  
  26. #include <proto/exec.h>
  27. #include <proto/intuition.h>
  28. #include <proto/graphics.h>
  29.  
  30. /* (private) class r_t, inherits from function */
  31. struct r_t {
  32.     struct function f;
  33.     char r[EXPRLEN], theta[EXPRLEN];
  34.     value r_t, theta_t, dr, dtheta;
  35. };
  36.  
  37. /* (private) class, inherits from point */
  38. struct point_r_t {
  39.     point p;
  40.     double r, theta, t;
  41. };
  42.  
  43. typedef struct point_r_t point_r_t;
  44.  
  45. /*-------------------------------------------------------------------------*/
  46. /*                        r_t class implementation                         */
  47. /*-------------------------------------------------------------------------*/
  48.  
  49. /* Is the function displayable ? */
  50. static int r_t_ok(const struct r_t *this)
  51. {
  52.     return this->f.min != NOVAL && this->f.max != NOVAL &&
  53.            this->f.min < this->f.max &&
  54.            (this->f.steps == INOVAL || this->f.steps >= 3);
  55. }
  56.  
  57. /* Free resources */
  58. static void destroy_r_t(struct r_t *this)
  59. {
  60.     free_var_list(&this->f.used);
  61.     if (this->f.calc) free_list(&this->f.pts, this->f.sizept);
  62.     this->f.calc = FALSE;
  63.     if (this->r_t) free_expr(this->r_t);
  64.     if (this->dr) free_expr(this->dr);
  65.     if (this->theta_t) free_expr(this->theta_t);
  66.     if (this->dtheta) free_expr(this->dtheta);
  67.     this->theta_t = this->r_t = this->dtheta = this->dr = NULL;
  68. }
  69.  
  70. /* Init dependant parts of function */
  71. static int create_r_t(struct r_t *this)
  72. {
  73.     this->f.calc = FALSE;
  74.     this->f.var.name = this->f.vname;
  75.     this->r_t = compile(this->r);
  76.     if (eval_error != 0)
  77.     {
  78.         message(this->f.o.g, "Compilation error in x(t):", eval_messages[eval_e
  79. rror], (char *)NULL);
  80.         return FALSE;
  81.     }
  82.     this->dr = differentiate(this->r_t, this->f.vname);
  83.     if (eval_error != NOT_DIFFERENTIABLE && eval_error != 0)
  84.     {
  85.         message(this->f.o.g, "Differentiation error (x):", eval_messages[eval_e
  86. rror], (char *)NULL);
  87.         return FALSE;
  88.     }
  89.     this->theta_t = compile(this->theta);
  90.     if (eval_error != 0)
  91.     {
  92.         message(this->f.o.g, "Compilation error in y(t):", eval_messages[eval_e
  93. rror], (char *)NULL);
  94.         return FALSE;
  95.     }
  96.     this->dtheta = differentiate(this->theta_t, this->f.vname);
  97.     if (eval_error != NOT_DIFFERENTIABLE && eval_error != 0)
  98.     {
  99.         message(this->f.o.g, "Differentiation error(y):", eval_messages[eval_er
  100. ror], (char *)NULL);
  101.         return FALSE;
  102.     }
  103.     if (!make_var_list(this->r_t, &this->f.used) || !make_var_list(this->theta_
  104. t, &this->f.used))
  105.         init_var_list(&this->f.used);
  106.     return TRUE;
  107. }
  108.  
  109. /* Allow user to define function */
  110. static int edit_r_t(struct r_t *this, struct Region **ref)
  111. {
  112.     struct Requester *req;
  113.     struct Memory *m;
  114.     struct Gadget *gl = NULL, *sd, *nd;
  115.     char from[NBLEN], to[NBLEN], steps[INTLEN], r[EXPRLEN], theta[EXPRLEN], tna
  116. me[VARLEN], colour[INTLEN];
  117.     int ret = FALSE;
  118.  
  119.     *ref = NULL;
  120.  
  121.     /* Create requester */
  122.     double2str(from, this->f.min);
  123.     double2str(to, this->f.max);
  124.     int2str(steps, this->f.steps);
  125.     int2str(colour, this->f.colour);
  126.     strcpy(r, this->r);
  127.     strcpy(theta, this->theta);
  128.     strcpy(tname, this->f.vname);
  129.  
  130.     if ((m = NewMemory()) &&
  131.         (req = InitReq(50, 20, 255, 165, m)) &&
  132.         SetReqBorder(req, 1, m) &&
  133.         AddIntuiText(&req->ReqText, "Function", 95, 6, m) &&
  134.         AddText(&gl, 0, "r(", FALSE, tname, VARLEN, TRUE, 0, RELVERIFY, 27, 20,
  135.  24, 10, TRUE, m) &&
  136.         AddText(&gl, 0, ")=", FALSE, r, EXPRLEN, TRUE, 0, RELVERIFY, 75, 20, 16
  137. 0, 10, TRUE, m) &&
  138.         AddText(&gl, 0, "theta()=", FALSE, theta, EXPRLEN, TRUE, 0, RELVERIFY,
  139. 75, 40, 160, 10, TRUE, m) &&
  140.         AddText(&gl, 0, "from ", FALSE, from, NBLEN, TRUE, 0, RELVERIFY, 51, 60
  141. , 80, 10, TRUE, m) &&
  142.         AddText(&gl, 0, "to ", FALSE, to, NBLEN, TRUE, 0, RELVERIFY, 169, 60, 8
  143. 0, 10, TRUE, m) &&
  144.         AddText(&gl, 0, "steps ", FALSE, steps, INTLEN, TRUE, 0, RELVERIFY, 59,
  145.  80, 32, 10, TRUE, m) &&
  146.         AddText(&gl, 0, "colour ", FALSE, colour, INTLEN, TRUE, 0, RELVERIFY, 1
  147. 56, 80, 32, 10, TRUE, m) &&
  148.         (sd = AddOption(&gl, 0, "Show discontinuities", TRUE, this->f.showdisc
  149. * SELECTED, 0, 11, 100, 10, 10, m)) &&
  150.         (nd = AddOption(&gl, 0, "Allow flat discontinuities", TRUE, this->f.nic
  151. edisc * SELECTED, 0, 11, 120, 10, 10, m)) &&
  152.         AddBox(&gl, TRUE, "Ok", 0, RELVERIFY | ENDGADGET, 40, 140, 65, 15, FALS
  153. E, m) &&
  154.         AddBox(&gl, FALSE, "Cancel", 0, RELVERIFY | ENDGADGET, 145, 140, 65, 15
  155. , FALSE, m))
  156.     {
  157.         SetReqGadgets(req, gl);
  158.         if (ret = DoRequest(req, this->f.o.g, std_ghandler))
  159.         {
  160.             *ref = full_refresh(this->f.o.g);
  161.  
  162.             /* Extract info */
  163.             this->f.min = str2double(from);
  164.             this->f.max = str2double(to);
  165.             this->f.steps = str2int(steps);
  166.             if ((this->f.colour = str2int(colour)) == INOVAL) this->f.colour =
  167. 1;
  168.             this->f.showdisc = (sd->Flags & SELECTED) != 0;
  169.             this->f.nicedisc = (nd->Flags & SELECTED) != 0;
  170.             strcpy(this->r, r);
  171.             strcpy(this->theta, theta);
  172.             strcpy(this->f.vname, tname);
  173.  
  174.             /* Create function */
  175.             destroy_r_t(this);
  176.             if (this->f.o.ok = r_t_ok(this)) this->f.o.ok = create_r_t(this);
  177.         }
  178.     }
  179.     Free(m);
  180.  
  181.     return ret;
  182. }
  183.  
  184. /* Calculate points of function */
  185. static int calc_r_t(struct r_t *this, int allow_mes)
  186. {
  187.     double t;
  188.     int i;
  189.     struct graph *const g = this->f.o.g;
  190.     double const tmin = this->f.min;
  191.     double const tmax = this->f.max;
  192.     int const steps = this->f.steps == INOVAL ? DEFSTEPS : this->f.steps;
  193.     double const step = (tmax - tmin) / (steps - 1);
  194.     static char func[FNAMELEN + 30];
  195.  
  196.     strcpy(func, "Can't calculate points for ");
  197.     strcat(func, this->f.o.name);
  198.     strcat(func, ":");
  199.  
  200.     new_list(&this->f.pts);
  201.  
  202.     if (!create_quick(&this->f.var))
  203.     {
  204.         if (allow_mes) message(g, func, "Couldn't create variable", (char *)NUL
  205. L);
  206.         else alert(g->io.win, func, "Couldn't create variable");
  207.         return FALSE;
  208.     }
  209.  
  210.     /* Calculate steps points, spread evenly from min to max */
  211.     for (i = 0, t = tmin; i < steps; i++, t += step)
  212.     {
  213.         point_r_t *pt = alloc_node(this->f.sizept);
  214.  
  215.         if (!pt)
  216.         { /* No mem */
  217.             free_list(&this->f.pts, this->f.sizept);
  218.             free_quick(&this->f.var);
  219.             if (allow_mes) message(g, func, "No memory", (char *)NULL);
  220.             else alert(g->io.win, func, "No memory");
  221.             return FALSE;
  222.         }
  223.         add_tail(&this->f.pts, pt);
  224.  
  225.         set_quick(&this->f.var, t);
  226.         pt->t = t;
  227.  
  228.         pt->r = quick_eval(this->r_t);
  229.         pt->p.state = (eval_error == 0) ? EXISTS : 0;
  230.         if (pt->p.state == EXISTS)
  231.         {
  232.             pt->theta = quick_eval(this->theta_t);
  233.             pt->p.state = (eval_error == 0) ? EXISTS : 0;
  234.             /* Polar -> Rect conversion */
  235.             pt->p.x = fabs(pt->r) * cos(pt->theta);
  236.             pt->p.y = fabs(pt->r) * sin(pt->theta);
  237.         }
  238.     }
  239.     free_quick(&this->f.var);
  240.     return TRUE;
  241. }
  242.  
  243. /* Try to improve look of function by adding points. If fails, decides that
  244.    there is a discontinuity */
  245. /* see f_of_x.c for details */
  246. static struct Region *improve_r_t(struct r_t *this)
  247. {
  248.     struct graph *const g = this->f.o.g;
  249.     point_r_t *pt, *next;
  250.     int ok = FALSE, iter, abort = FALSE;
  251.     double flatx = FLAT * (g->a.y.max - g->a.y.min) / g->io.win->Height;
  252.     double flaty = FLAT * (g->a.x.max - g->a.x.min) / g->io.win->Width;
  253.     char msg[FNAMELEN + 30];
  254.     char pass[20];
  255.     struct Requester *req;
  256.     struct Region *full = NULL;
  257.  
  258.     /* Flat has no meaning when graph incorrect */
  259.     if (!this->f.o.g->ok) flatx = flaty = 0.0;
  260.  
  261.     if (!this->f.calc)
  262.     {
  263.         strcpy(msg, this->f.o.name);
  264.         strcpy(msg, "not calculated!");
  265.         message(g, msg, (char *)NULL);
  266.         return NULL;
  267.     }
  268.     if (!this->dr || !this->dtheta)
  269.     {
  270.         strcpy(msg, this->f.o.name);
  271.         strcat(msg, " wasn't differentiable");
  272.         message(g, msg, (char *)NULL);
  273.         return NULL;
  274.     }
  275.     if (!create_quick(&this->f.var))
  276.     {
  277.         message(g, "Couldn't create variable", (char *)NULL);
  278.         return NULL;
  279.     }
  280.  
  281.     if (!(req = abort_request(g, "Improve: Pass 1")))
  282.         message(g, "No Memory !", (char *)NULL);
  283.     else
  284.     {
  285.         full = full_refresh(this->f.o.g);
  286.  
  287.         for (iter = 1; iter <= MAXITER && !ok && !abort; iter++)
  288.         {
  289.             sprintf(pass, "Improve: Pass %d", iter);
  290.             set_abort_msg(req, pass);
  291.             ok = TRUE;
  292.  
  293.             for (pt = first(&this->f.pts); succ(next = succ(pt)); pt = next)
  294.             {
  295.                 if ((pt->p.state & (EXISTS | OK)) == EXISTS) /* Only exists */
  296.                 {
  297.                     double dr, dtheta, dt;
  298.  
  299.                     pt->p.state |= OK;
  300.                     pt->p.state &= ~DISC;
  301.  
  302.                     dt = next->t - pt->t;
  303.                     set_quick(&this->f.var, pt->t);
  304.                     dr = quick_eval(this->dr);
  305.                     if (eval_error == 0)
  306.                     {
  307.                         dtheta = quick_eval(this->dtheta);
  308.                         if (eval_error == 0)
  309.                         {
  310.                             double c = cos(pt->theta);
  311.                             double s = sin(pt->theta);
  312.                             /* A little elementary calculus ... */
  313.                             double dx = dr * c - pt->r * dtheta * s;
  314.                             double dy = dr * s + pt->r * dtheta * c;
  315.                             double ecartx = next->p.x - pt->p.x;
  316.                             double errorx = fabs(ecartx - dt * dx);
  317.                             double ecarty = next->p.y - pt->p.y;
  318.                             double errory = fabs(ecarty - dt * dy);
  319.  
  320.                             /* Check both axes */
  321.                             if ((errorx > fabs(ecartx) * MAXERROR && (!this->f.
  322. nicedisc || errorx > flatx)) ||
  323.                                 (errory > fabs(ecarty) * MAXERROR && (!this->f.
  324. nicedisc || errory > flaty)))
  325.                             {
  326.                                 pt->p.state &= ~OK;
  327.                                 ok = FALSE;
  328.  
  329.                                 if (iter == MAXITER) pt->p.state |= DISC;
  330.                                 else /* cut interval in 2 */
  331.                                 {
  332.                                     point_r_t *newpt = alloc_node(this->f.sizep
  333. t);
  334.  
  335.                                     if (!newpt)
  336.                                     {
  337.                                         nomem(g->io.win);
  338.                                         abort = TRUE;
  339.                                         break;
  340.                                     }
  341.  
  342.                                     newpt->t = (pt->t + next->t) / 2;
  343.                                     set_quick(&this->f.var, newpt->t);
  344.  
  345.                                     newpt->r = quick_eval(this->r_t);
  346.                                     newpt->p.state = (eval_error == 0) ? EXISTS
  347.  : 0;
  348.                                     if (newpt->p.state == EXISTS)
  349.                                     {
  350.                                         newpt->theta = quick_eval(this->theta_t
  351. );
  352.                                         newpt->p.state = (eval_error == 0) ? EX
  353. ISTS : 0;
  354.                                         newpt->p.x = fabs(newpt->r) * cos(newpt
  355. ->theta);
  356.                                         newpt->p.y = fabs(newpt->r) * sin(newpt
  357. ->theta);
  358.                                     }
  359.                                     insert(&this->f.pts, newpt, pt);
  360.                                 }
  361.                             }
  362.                         }
  363.                     }
  364.                 }
  365.             }
  366.         }
  367.         end_abort_request(req);
  368.     }
  369.     free_quick(&this->f.var);
  370.     return full;
  371. }
  372.  
  373. /* String representation of function */
  374. static char *f2str_r_t(struct r_t *this, char *buf, int maxlen)
  375. {
  376.     buf[maxlen - 1] = '\0';
  377.     strncpy(buf, this->f.o.name, maxlen - 1);
  378.     strncat(buf, ": r(", maxlen - strlen(buf) - 1);
  379.     strncat(buf, this->f.vname, maxlen - strlen(buf) - 1);
  380.     strncat(buf, ")=", maxlen - strlen(buf) - 1);
  381.     strncat(buf, this->r, maxlen - strlen(buf) - 1);
  382.     strncat(buf, ", theta(", maxlen - strlen(buf) - 1);
  383.     strncat(buf, this->f.vname, maxlen - strlen(buf) - 1);
  384.     strncat(buf, ")=", maxlen - strlen(buf) - 1);
  385.     strncat(buf, this->theta, maxlen - strlen(buf) - 1);
  386.  
  387.     return buf;
  388. }
  389.  
  390. /* Save local data to file */
  391. static int save_r_t(struct r_t *this, FILE *f)
  392. {
  393.     short tag = R_T_TAG;
  394.     short end = R_T_END;
  395.  
  396.     return WRITE(f, tag) &&
  397.            WRITE(f, this->r) &&
  398.            WRITE(f, this->theta) &&
  399.            WRITE(f, end);
  400. }
  401.  
  402. /* free function */
  403. static struct Region *delete_r_t(struct r_t *this)
  404. {
  405.     struct Region *full = full_refresh(this->f.o.g);
  406.  
  407.     destroy_r_t(this);
  408.     FreeMem(this, sizeof(struct r_t));
  409.  
  410.     return full;
  411. }
  412.  
  413. /* Create a new function */
  414. struct r_t *new_r_t(struct graph *g, char *name)
  415. {
  416.     struct r_t *this = AllocMem(sizeof(struct r_t), MEMF_CLEAR);
  417.  
  418.     if (this)
  419.     {
  420.         /* Standard init */
  421.         init_function(&this->f, g, name);
  422.         /* Local methods */
  423.         this->f.o.delete = (void *)delete_r_t;
  424.         this->f.o.edit = (void *)edit_r_t;
  425.         this->f.o.improve = (void *)improve_r_t;
  426.         this->f.o.f2str = (void *)f2str_r_t;
  427.         this->f.calcf = (void *)calc_r_t;
  428.         this->f.save = (void *)save_r_t;
  429.         this->f.sizept = sizeof(point_r_t);
  430.         return this;
  431.     }
  432.     message(g, "Couldn't create function:", "No memory", (char *)NULL);
  433.     return NULL;
  434. }
  435.  
  436. /* load from file */
  437. struct r_t *load_r_t(struct graph *g, FILE *f)
  438. {
  439.     struct r_t *this = new_r_t(g, "");
  440.  
  441.     if (this)
  442.     {
  443.         short end;
  444.  
  445.         /* Read local data */
  446.         if (READ(f, this->r) &&
  447.             READ(f, this->theta) &&
  448.             READ(f, end) &&
  449.             end == R_T_END)
  450.         {
  451.             load_rest(&this->f, f); /* Read standard data */
  452.             if (this->f.o.ok = r_t_ok(this)) this->f.o.ok = create_r_t(this);
  453.  
  454.             return this;
  455.         }
  456.         delete_r_t(this);
  457.     }
  458.     return NULL;
  459. }
  460.  
  461.